#include "console-common.h"
#include "lua-font.h"
#include "lua-conwin.h"
#include "lua-extra-attr.h"
#include <algorithm>
#include <cstdlib>

BLINK_FLAGS_TYPE *sdl_blinking_flags_0 = NULL, *sdl_blinking_flags_1 = NULL, *sdl_blinking_flags_curr = NULL;

int luacon_blinking_period[2] = {30, 30};

#define enum_console(i, j)	{ for (j = 0; j < YCHRS; j++) for (i = 0; i < XCHRS; i++) {
#define enum_console_end	}}

#ifdef USE_FASM
void __sdl_translate_draw_blockic_asm() __asm__(".sdl_translate_draw_blockic.asm");
#endif

#ifdef __GNUC__
__attribute__((regparm(3)))
#else
__fastcall
#endif
void sdl_translate_boxdraw(uint32_t* dst, int32_t fc, int32_t bc, int c)
{
	int i, j;

	for (i = 0; i < CHRH; i++)
		std::fill_n(dst+i*(XRES), CHRW, bc);
	if (!(c&0x1B)) return; // XXXABXCD
	
	int cH = c & 7, cV = (c >> 3) & 7;
	int _hDouble = ((cH > 4) ? 1 : 0),
		_vDouble = ((cV > 4) ? 1 : 0);

	for (i = -_hDouble; i < 2; i += 2)
	{
		uint32_t * b = dst + (XRES)*((CHRH/2)+i);
		
		for (j = -_vDouble; j < 2; j += 2)
			b[(CHRW/2)+j] = fc;

		if (cH & 0x1) // left
			std::fill(b, b+(CHRW/2)-_vDouble, fc);
		if (cH & 0x2) // right
			std::fill(b+(CHRW/2)+_vDouble+1, b+CHRW, fc);
	}
	for (j = -_vDouble; j < 2; j += 2)
	{
		uint32_t * b = dst + (CHRW/2) + j;
		
		if (cV & 0x1) // up
			for (int j = 0; j < (CHRH/2)-_hDouble; j++)
				b[(XRES)*j] = fc;
		if (cV & 0x2) // down
			for (int j = (CHRH/2)+_hDouble+1; j < CHRH; j++)
				b[(XRES)*j] = fc;
	}
	
	if (_hDouble)
	{
		if (_vDouble)
		{
			if (!(cH & 0x1))
				dst[((CHRW/2)-1)+(XRES)*(CHRH/2)] = fc;
			if (!(cH & 0x2))
				dst[((CHRW/2)+1)+(XRES)*(CHRH/2)] = fc;
			if (!(cV & 0x1))
				dst[(CHRW/2)+(XRES)*((CHRH/2)-1)] = fc;
			if (!(cV & 0x2))
				dst[(CHRW/2)+(XRES)*((CHRH/2)+1)] = fc;
		}
		else if ((0xFF777711 >> (c & 0x1F)) & 1)
			goto drawcntr;
	}
	else if ((0x88EEEEFF >> (c & 0x1F)) & 1)
	{
	drawcntr:
		dst[(CHRW/2)+(XRES)*(CHRH/2)] = fc;
	}
}

#if defined(__GNUC__) || defined(_MSC_VER)
__declspec(noinline)
#endif
void sdl_translate_map(int32_t* text_buf, unsigned int * vid, int flags)
{
	int fg, bg, chr, src = 0;
	int i, j, i2, j2;
	fontdata_column_t b;
	fontdata_t b_ptr;

	enum_console(i, j)
		chr = text_buf[src] & ((1 << FONT_NUM_CHAR_BITS) - 1);
		fg  = text_buf[src+1];
		bg  = text_buf[src+2];
		b_ptr = ascii_font_ptr[chr];
		if (b_ptr != NULL)
			for (i2 = 0; b = b_ptr[i2], i2 < CHRW; i2++)
				for (j2 = 0; j2 < CHRH; j2++)
					vid[(i*CHRW+i2)+(XRES)*(j*CHRH+j2)] = (
						(b & (1 << (CHRH - 1 - j2))) ? fg : bg
					);
		else for (j2 = 0; j2 < CHRH; j2++)
			std::fill_n(&vid[(i*CHRW)+(XRES)*(j*CHRH+j2)], CHRW, bg);
		src += (SSKIP/4);
	enum_console_end

	if (sdl_blinking_flags_curr != NULL)
	{
		static int blink_timeout = 0;
		static bool blink_state = false;
		if (blink_timeout)
			blink_timeout--;
		else
			blink_timeout = luacon_blinking_period[blink_state ? 0 : 1],
			blink_state = !blink_state;
		int oset = 0;
		enum_console(i, j)
			int k = sdl_blinking_flags_curr[j * XCHRS + i];
			if (k) // && !(k & BFLAG_DISABLE)
			{
				if ((k & BFLAG_BLINKING) && blink_state)
				{
					int color = text_buf[oset + 2];
					for (j2 = 0; j2 < CHRH; j2++)
						std::fill_n(&vid[(i*CHRW)+(XRES)*(j*CHRH+j2)], CHRW, color);
				}
				else if (k & BFLAG_BLOCKIC)
				{
					int32_t fc = text_buf[oset + 1];
					int32_t bc = text_buf[oset + 2];
					unsigned int *_dest = &vid[(i*CHRW)+(XRES)*(j*CHRH)];
					int _ch = text_buf[oset];
					oset += (SSKIP/4);
					
					if (k & BFLAG_BOXDRAW)
					{
						sdl_translate_boxdraw(_dest,fc,bc,_ch);
						continue;
					}
#ifdef USE_FASM
					int dummy;
					__asm__ __volatile__ (
						"call %P5"
						: "=a"(dummy), "=b"(dummy), "=c"(dummy), "=d"(dummy), "=D"(dummy)
						: "m"(__sdl_translate_draw_blockic_asm),
						  "0"(_ch), "1"(4 * XRES), "2"(fc), "3"(bc), "4"(_dest)
						: "esi",
						  "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "cc", "memory"
					);
#else
					for (int _a = 7; _a >= 0; )
					{
						int _lc, _rc;
#if defined(X86) && defined(__GNUC__) && (CHRW == 8) && ((CHRH % 4) == 0)

						// 预期: 方向标志位 (DF) 已清除

						int _counter = CHRH / 4;
						
						__asm__ __volatile__ (
							"mov %4, %0;"
							"bt %2, %5;"
							"cmovc %3, %0;"
							"decl %2;"
							"bt %2, %5;"
							"cmovc %3, %1;"
							"decl %2;"
							: "=&r"(_lc), "=r"(_rc), "+r"(_a)
							: "r"(fc), "1"(bc), "r"(_ch)
							: "cc", "memory"
						);

						// _lc 和 _rc 使用快速寄存器
						__asm__ __volatile__ (	// MOV EDI, _dest
#if (CHRH == 16)
							"movd %1, %%xmm2;"	// MOVD XMM0, _lc
							"movd %2, %%xmm3;"	// MOVD XMM1, _rc
							"pshufd $0, %%xmm2, %%xmm0;"
							"pshufd $0, %%xmm3, %%xmm1;"
							"movups %%xmm0, (%0);"
							"movups %%xmm1, %c3(%0);"
							"movups %%xmm0, %c4(%0);"
							"movups %%xmm1, %c5(%0);"
							"movups %%xmm0, %c6(%0);"
							"movups %%xmm1, %c7(%0);"
							"movups %%xmm0, %c8(%0);"
							"movups %%xmm1, %c9(%0);"
							"add %10, %0;"		// ADD EDI, 16 * XRES
#else
							".L%=_loop:"		// _loop:
							"mov %2, %%eax;"	// MOV EAX, _lc
							"stosl; stosl;"
							"stosl; stosl;"		// STOSD * 4
							"mov %3, %%eax;"	// MOV EAX, _rc
							"stosl; stosl;"
							"stosl; stosl;"		// STOSD * 4
							"add %4, %0;"		// ADD EDI, 4 * (XRES - 8)
							"decl %1;"			// DEC _counter
							"jnz .L%=_loop;"	// JNZ _loop
												// MOV _dest, EDI
#endif

#if (CHRH == 16)	
							: "+r"(_dest)							// 输出操作数 
							: "r"(_lc), "r"(_rc),					// 输入操作数 
							  "i"(2 * CHRW), "i"(4 * XRES),
							  "i"(2 * CHRW + 4 * XRES), "i"(8 * XRES),
							  "i"(2 * CHRW + 8 * XRES), "i"(12 * XRES),
							  "i"(2 * CHRW + 12 * XRES), "i"(16 * XRES)
							: "xmm0", "xmm1", "xmm2", "xmm3",
							  "cc", "memory" 						// 被破坏的寄存器 
#else
							: "+D"(_dest)							// 输出操作数 
							: "rm"(_counter), "r"(_lc), "r"(_rc),	// 输入操作数 
							  "i"(4 * (XRES - CHRW))				
							: "eax", "cc", "memory"					// 被破坏的寄存器 
#endif
						);
#else
						// "decompiled" code

						int _i = (7 - _a) >> 2, _s, _e, _h = CHRW / 2;
						_lc = (_ch & (1 << _a)) ? fc : bc;
						_rc = (_ch & (1 << (_a - 1))) ? fc : bc;
						_a -= 2;
						_s = (_i * CHRH + 2) >> 2;
						_e = ((_i + 1) * CHRH + 2) >> 2;

						for (int _j = _s; _j < _e; _j++)
						{
							std::fill_n(_dest, _h, color);
							std::fill_n(_dest + _h, CHRW - _h, color);
						}
						_dest += XRES;
#endif
					}
#endif
					continue;
				}

				int fc = text_buf[oset + 1];

				if (k & BFLAG_UNDERSC)
					std::fill_n(&vid[(i*CHRW)+(XRES)*((j+1)*CHRH-1)], CHRW, fc);
				if (k & BFLAG_OVERLINE)
					std::fill_n(&vid[(i*CHRW)+(XRES)*(j*CHRH)], CHRW, fc);
				if (k & BFLAG_LVERTICAL)
					for (j2 = 0; j2 < CHRH; j2++)
						vid[(i*CHRW)+(XRES)*(j*CHRH+j2)] = fc;
				if (k & BFLAG_RVERTICAL)
					for (j2 = 0; j2 < CHRH; j2++)
						vid[((i+1)*CHRW-1)+(XRES)*(j*CHRH+j2)] = fc;
			}
			oset += (SSKIP/4);
		enum_console_end
	}
}